#include <Windows.h>
#include <stdlib.h>
//#include <tcNetwork/tc_network.h>
#include <tcLogic/tc_logic.h>
#include <tcSound/tc_sound.h>
#include <tcDatabase/tc_chessboard.h>
#include <tcPhysics/tc_physics.h>

//add a struct for entire game

#pragma warning(disable: 4244)

#define DEAD_CHESSMEN_BUFFER_SIZE 32

enum
{
	TC_PROP_POWERUP_SCORE = 10,
	TC_PROP_FORBID_SCORE = 18,
	TC_PROP_ENLARGE_SCORE = 26,
	TC_CHANGE_NEED_SCORE = 40,
};

typedef struct 
{
	tcType player_id;
	int chessmen_left;
	int score;
} tc_player;

static BOOL g_valid;
static tc_player* g_current_player;
static tcType g_game_state;

static int g_selected_chessman = -1;

static tc_player g_players[2];
static int g_dead_chessmen_buffer[DEAD_CHESSMEN_BUFFER_SIZE];

static float pos_offsets[2][16] = {
	0, 1, -1, 2, -2, 3, -3, 4, -4, 3, -3, 0, 2, -2, 4, -4,
	3.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 2.5, 2.5, 1.5, 1.5, 1.5, 1.5, 1.5,
};

static tcType sizes[16] = {
	TC_CHESSMAN_SIZE_LARGE, TC_CHESSMAN_SIZE_SMALL, TC_CHESSMAN_SIZE_SMALL, TC_CHESSMAN_SIZE_MIDDLE,
	TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_MIDDLE,
	TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_MIDDLE, TC_CHESSMAN_SIZE_SMALL,
	TC_CHESSMAN_SIZE_SMALL, TC_CHESSMAN_SIZE_SMALL, TC_CHESSMAN_SIZE_SMALL, TC_CHESSMAN_SIZE_SMALL,
};

static void init_players()
{
	g_players[TC_PLAYER_ONE].player_id = TC_PLAYER_ONE;
	g_players[TC_PLAYER_TWO].player_id = TC_PLAYER_TWO;
}

static void init_chessmen()
{
	int i = 0;
	tc_chessman_init_desc desc;
	tcType size;
	tcType owner;
	int id;
	for (; i < TC_CHESSMEN_MAX_NUMBER; i++)
	{
		size = sizes[i%16];
		owner = (i < 16 ? TC_PLAYER_ONE : TC_PLAYER_TWO);

		desc.init_owner = owner;
		desc.init_size = size;
		id = tc_chessman_create(&desc);
		tc_chessman_create_body(id);
	}
}

static void reset_players()
{
	g_players[TC_PLAYER_ONE].score = 0;
	g_players[TC_PLAYER_ONE].chessmen_left = 16;

	g_players[TC_PLAYER_TWO].score = 0;
	g_players[TC_PLAYER_TWO].chessmen_left = 16;
}

static void reset_chessmen_position()
{
	int i = 0;
	tc_vector2 position;
	for (; i < TC_CHESSMEN_MAX_NUMBER; i++)
	{
		position.x = TC_SCREEN_WIDTH/2 + TC_LATTICE_WIDTH * pos_offsets[0][i%16];
		position.y = TC_SCREEN_HEIGHT/2 + TC_LATTICE_HEIGHT * pos_offsets[1][i%16] * (i < 16 ? -1 : 1);
		tc_chessman_set_transform(i, position, 0);
		tc_chessman_set_body_active(i, true);
		tc_physics_adjust_body_size(i);
	}
}

static void reset_chessmen()
{
	int id = 0;
	for (; id < TC_CHESSMEN_MAX_NUMBER; id++)
	{
		tc_chessman_reset(id);
	}

	reset_chessmen_position();
}

static void dead_chessmen_buffer_clear()
{
	int i = 0;
	for (; i < DEAD_CHESSMEN_BUFFER_SIZE; i++) {
		g_dead_chessmen_buffer[i] = -1;
	}
}

static void dead_chessmen_buffer_append(int id)
{
	int i = 0;
	for (; i < DEAD_CHESSMEN_BUFFER_SIZE; i++) {
		if (g_dead_chessmen_buffer[i] == -1)
		{
			g_dead_chessmen_buffer[i] = id;
			break;
		}
	}
}

static VOID dead_chessmen_buffer_flush()
{
	int i = 0;
	int id = 0;
	for (; i < DEAD_CHESSMEN_BUFFER_SIZE; i++) {
		id = g_dead_chessmen_buffer[i];
		if (id != -1) {
			tc_chessman_set_body_active(id, false);
		}
		else {
			break;
		}
	}
	dead_chessmen_buffer_clear();
}

void tc_logic_init()
{
	init_chessmen();
	init_players();
}

void tc_logic_exit()
{

}

void tc_logic_restart( tcType player )
{
	g_current_player = &g_players[player];
	g_valid = true;
	g_game_state = TC_GS_FIGHTING;
	
	
	reset_chessmen();
	reset_players();
	dead_chessmen_buffer_clear();
	tc_logic_select_chessman(TC_CHESSMAN_NULL);

	tc_sound_play(TC_SND_START);
}

tcType tc_logic_get_current_player()
{
	return g_current_player->player_id;
}

BOOL tc_logic_select_chessman(int id)
{
	if (g_game_state == TC_GS_USING_ENLARGE_PROP)
	{
		if (tc_chessman_get_owner(id) == tc_logic_get_current_player())
		{
			if (tc_chessman_enlarge(id))
			{
				tc_sound_play(TC_SND_CHANGE_EF);
				tc_physics_adjust_body_size(id);
				g_game_state = TC_GS_FIGHTING;
			}
		}
		return false;
	}
	if (g_game_state == TC_GS_USING_CHANGE_PROP)
	{
		if (tc_chessman_get_owner(id) != tc_logic_get_current_player())
		{
			tc_sound_play(TC_SND_CHANGE_EF);
			tc_chessman_change(id);
			g_players[tc_logic_get_current_player()].chessmen_left++;
			g_players[!tc_logic_get_current_player()].chessmen_left--;
			g_game_state = TC_GS_FIGHTING;
		}
		return false;
	}

	g_selected_chessman = id;
	
	if (g_selected_chessman != TC_CHESSMAN_NULL)
	{
		tc_sound_play(TC_SND_SELECT);
	}

	return true;
}


int tc_logic_get_selected_chessman()
{
	return g_selected_chessman;
}


void tc_logic_shoot_chessman( int id, tc_vector2 impulse )
{
	if (tc_logic_get_game_state() == TC_GS_USING_POWERUP_PROP)
	{
		g_game_state = TC_GS_FIGHTING;
	}
	tc_chessman_apply_impulse(id, impulse);
	tc_sound_play(TC_SND_FIRE);
	g_valid = false;
}

tcType tc_logic_get_game_state()
{
	return g_game_state;
}

BOOL tc_logic_get_valid()
{
	return g_valid;
}

BOOL tc_logic_get_chessman_valid(int id)
{
	tcType owner;
	if (g_valid)
	{
		if (tc_chessman_get_dead(id))
		{
			return false;
		}

		owner = tc_chessman_get_owner(id);

		if (g_game_state == TC_GS_USING_CHANGE_PROP) {
			return !(owner == g_current_player->player_id ? true : false);
		}
		else {
			return owner == g_current_player->player_id ? true : false;
		}
	}
	else {
		return false;
	}
}

static void switch_player()
{
	tc_sound_play(TC_SND_MYTURN);
	if (g_game_state == TC_GS_USING_FORBID_PROP)
	{
		g_game_state = TC_GS_FIGHTING;
	}
	else
	{
		g_current_player->player_id = !g_current_player->player_id;
	}
}

static void chessman_died(int id)
{
	int value;
	int owner;

	dead_chessmen_buffer_append(id);
	tc_chessman_set_dead(id, true);

	value = tc_chessman_get_value(id);
	owner = tc_chessman_get_owner(id);

	g_players[owner].chessmen_left--;
	g_players[owner].score += value;

	if (owner != g_current_player->player_id)
	{
		g_current_player->score += (int)(value/2);
	}
}

static void check_dead()
{
	int id = 0;
	for (; id < TC_CHESSMEN_MAX_NUMBER; id++)
	{
		BOOL dead = tc_chessman_get_dead(id);
		if (!dead)
		{
			tc_vector2 position;
			tc_chessman_get_position(id, &position);
			if (abs(position.x - TC_SCREEN_WIDTH/2) > TC_CHESSBOARD_WIDTH/2 ||
				abs(position.y - TC_SCREEN_HEIGHT/2) > TC_CHESSBOARD_HEIGHT/2)
			{
				chessman_died(id);
				tc_sound_play(TC_SND_DROP);
			}
		}
	}
}

static BOOL check_valid()
{
	int id = 0;
	BOOL ret = true;
	for (; id < TC_CHESSMEN_MAX_NUMBER; id++)
	{
		if (!tc_chessman_get_dead(id))
		{
			tc_vector2 velocity;
			tc_chessman_get_velocity(id, &velocity);
			if (tc_vector2_length(velocity) >= 0.1f)
			{
				ret = false;
				break;
			}
		}
	}
	return ret;
}

static void check_game_over()
{
	if (!g_players[TC_PLAYER_ONE].chessmen_left)
	{
		if (!g_players[TC_PLAYER_TWO].chessmen_left)
		{
			g_game_state = TC_GS_TIE;
		}
		else {
			tc_sound_play(TC_SND_LOSE);
			g_game_state = TC_GS_PLAYER_TWO_WIN;
		}
	}
	else
	{
		if (!g_players[TC_PLAYER_TWO].chessmen_left)
		{
			tc_sound_play(TC_SND_WIN);
			g_game_state = TC_GS_PLAYER_ONE_WIN;
		}
	}
}

static void check_turn()
{
	if (!g_valid)
	{
		g_valid = check_valid();
		if (g_valid)
		{
			check_game_over();
			if (g_game_state != TC_GS_PLAYER_ONE_WIN && g_game_state != TC_GS_PLAYER_TWO_WIN)
			{
				dead_chessmen_buffer_flush();
				switch_player();
			}
		}
	}
}

void tc_logic_update(float dt)
{
	tc_physics_update(dt);

	if (g_game_state != TC_GS_PLAYER_ONE_WIN && g_game_state != TC_GS_PLAYER_TWO_WIN)
	{
		check_dead();
		check_turn();
	}
}

int tc_logic_get_prop_score( tcType prop_type )
{
	int scores[] = {TC_PROP_POWERUP_SCORE, TC_PROP_FORBID_SCORE, TC_PROP_ENLARGE_SCORE, TC_CHANGE_NEED_SCORE};
	return scores[prop_type];
}

int tc_logic_get_player_score( tcType player )
{
	return g_players[player].score;
}

BOOL tc_logic_use_prop( tcType prop_type, tcType player )
{
	int prop_score;

	if (!tc_logic_get_valid())
	{
		return false;
	}

	if (player != tc_logic_get_current_player())
	{
		return false;
	}

	prop_score = tc_logic_get_prop_score(prop_type);
	if (g_current_player->score < prop_score)
	{
		return false;
	}
	
	g_current_player->score -= prop_score;

	switch (prop_type) {
	case TC_PROP_POWERUP:
		g_game_state = TC_GS_USING_POWERUP_PROP;
		tc_sound_play(TC_SND_POWERUP);
		break;
	case TC_PROP_FORBID:
		g_game_state = TC_GS_USING_FORBID_PROP;
		tc_sound_play(TC_SND_FORBID);
		break;
	case TC_PROP_ENLARGE:
		g_game_state = TC_GS_USING_ENLARGE_PROP;
		tc_sound_play(TC_SND_ENLARGE);
		break;
	case TC_PROP_CHANGE:
		g_game_state = TC_GS_USING_CHANGE_PROP;
		tc_sound_play(TC_SND_CHANGE);
		break;
	}

	return true;
}


